package com.vip.jwt.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.vip.jwt.common.entity.R;
import com.vip.jwt.common.exception.ExceptionEnum;
import com.vip.jwt.common.utils.JwtUtil;
import com.vip.jwt.common.utils.RedisUtil;
import com.vip.jwt.common.utils.ServlertUtil;
import lombok.Getter;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

public class JwtFilter extends AccessControlFilter {

    @Getter
    private final static String AUTHORIZATION = "Authorization";
    @Getter
    private final static String PLATFORM = "Platform";

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o){
        //解决跨域问题
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        //跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return true;
        }
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse){
        //这个地方和前端约定，要求前端将token放在请求的Header部分
        //所以以后发起请求的时候就需要在Header中放一个Authorization，值就是对应的Token
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String token = request.getHeader(AUTHORIZATION);
        if(StrUtil.isEmpty(token)){
            error(servletResponse,ExceptionEnum.NO_TOKEN);
            return false;
        }
        String username = JwtUtil.getUsername(token);
        String cacheToken = RedisUtil.get(token);
        if(StrUtil.isNotEmpty(cacheToken)){
            //给token续命，重新计时时间
            String newToken = JwtUtil.createToken(username);
            RedisUtil.set(token,newToken);
            RedisUtil.expire(token,7, TimeUnit.DAYS);
            return true;
        }else{
            error(servletResponse,ExceptionEnum.TOKEN_FAILURE);
            return false;
        }
    }

    /**
     *  OPTION跨域预检
     * @param response
     */
    private void success(ServletResponse response){
        String msgStr = "OPTION跨域请求预检成功";
        R r = R.ok().code(HttpStatus.OK.value()).message(msgStr);
        String msg = JSONUtil.toJsonStr(r);
        ((HttpServletResponse)response).setStatus(HttpStatus.OK.value());
        ServlertUtil.outputSteam(msg,response);
    }

    /**
     * 验证错误
     * @param response
     */
    private void error(ServletResponse response, ExceptionEnum exceptionEnum){
        R r = R.error().code(exceptionEnum.getCode()).message(exceptionEnum.getMessage());
        String msg = JSONUtil.toJsonStr(r);
        ((HttpServletResponse)response).setStatus(exceptionEnum.getCode());
        ServlertUtil.outputSteam(msg,response);
    }

}
